package com.google.gwt.widgets.client;

import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.i18n.client.BidiUtils;
import com.google.gwt.i18n.client.HasDirection;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;

/**
 * A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
 *
 * This widget uses a &lt;div&gt; element, causing it to be displayed with
 * block layout.
 *
 * <h3>CSS Style Rules</h3>
 * <ul class='css'>
 * <li>.gwt-Label { }</li>
 * </ul>
 *
 * <p>
 * <h3>Example</h3>
 * {@example com.google.gwt.examples.HTMLExample}
 * </p>
 */
public class SpanLabel
		extends Widget
		implements SourcesClickEvents, SourcesMouseEvents, SourcesMouseWheelEvents, HasHorizontalAlignment, HasText, HasWordWrap, HasDirection {

	/**
	 * Creates a Label widget that wraps an existing &lt;div&gt; or &lt;span&gt;
	 * element.
	 *
	 * This element must already be attached to the document.
	 *
	 * @param element the element to be wrapped
	 * @return SpanLabel
	 */
	public static SpanLabel wrap(com.google.gwt.dom.client.Element element) {

		// Assert that the element is of the correct type and is attached.
		assert element.getTagName().equalsIgnoreCase("div") || element.getTagName().equalsIgnoreCase("span");
		assert Document.get().getBody().isOrHasChild(element);

		SpanLabel label = new SpanLabel((Element)element);

		// Mark it attached and remember it for cleanup.
		label.onAttach();
		RootPanel.detachOnWindowClose(label);

		return label;

	}

	private ClickListenerCollection clickListeners;
	private HorizontalAlignmentConstant horzAlign;
	private MouseListenerCollection mouseListeners;
	private MouseWheelListenerCollection mouseWheelListeners;

	/**
	 * Creates an empty label.
	 */
	public SpanLabel() {
		setElement(DOM.createDiv());
		setStyleName("gwt-Label");
	}

	/**
	 * Creates a label with the specified text.
	 *
	 * @param text the new label's text
	 */
	public SpanLabel(String text) {
		this();
		setText(text);
	}

	/**
	 * Creates a label with the specified text.
	 *
	 * @param text the new label's text
	 * @param wordWrap <code>false</code> to disable word wrapping
	 */
	public SpanLabel(String text, boolean wordWrap) {
		this(text);
		setWordWrap(wordWrap);
	}

	/**
	 * This constructor is used to let the HTML constructors avoid work.
	 *
	 * @param element element
	 */
	SpanLabel(Element element) {
		setElement(element);
	}

	//=========================================================================
	/**
	 * Method addClickListener
	 * @param listener
	 */
	//=========================================================================
	public void addClickListener(ClickListener listener) {

		if (clickListeners == null) {
			clickListeners = new ClickListenerCollection();
			sinkEvents(Event.ONCLICK);
		}
		clickListeners.add(listener);

	}

	//=========================================================================
	/**
	 * Method addMouseListener
	 * @param listener
	 */
	//=========================================================================
	public void addMouseListener(MouseListener listener) {

		if (mouseListeners == null) {
			mouseListeners = new MouseListenerCollection();
			sinkEvents(Event.MOUSEEVENTS);
		}
		mouseListeners.add(listener);

	}

	//=========================================================================
	/**
	 * Method addMouseWheelListener
	 * @param listener
	 */
	//=========================================================================
	public void addMouseWheelListener(MouseWheelListener listener) {

		if (mouseWheelListeners == null) {
			mouseWheelListeners = new MouseWheelListenerCollection();
			sinkEvents(Event.ONMOUSEWHEEL);
		}
		mouseWheelListeners.add(listener);

	}

	//=========================================================================
	/**
	 * Method getDirection
	 * @return Direction
	 */
	//=========================================================================
	public Direction getDirection() {
		return BidiUtils.getDirectionOnElement(getElement());
	}

	//=========================================================================
	/**
	 * Method getHorizontalAlignment
	 * @return HorizontalAlignmentConstant
	 */
	//=========================================================================
	public HorizontalAlignmentConstant getHorizontalAlignment() {
		return horzAlign;
	}

	//=========================================================================
	/**
	 * Method getText
	 * @return String
	 */
	//=========================================================================
	public String getText() {
		return DOM.getInnerText(getElement());
	}

	//=========================================================================
	/**
	 * Method getWordWrap
	 * @return boolean
	 */
	//=========================================================================
	public boolean getWordWrap() {
		return !DOM.getStyleAttribute(getElement(), "whiteSpace").equals("nowrap");
	}

	//=========================================================================
	/**
	 * Method onBrowserEvent
	 * @param event
	 */
	//=========================================================================
	@Override
	public void onBrowserEvent(Event event) {

		switch (DOM.eventGetType(event)) {
			case Event.ONCLICK:
				if (clickListeners != null) {
					clickListeners.fireClick(this);
				}
				break;

			case Event.ONMOUSEDOWN:
			case Event.ONMOUSEUP:
			case Event.ONMOUSEMOVE:
			case Event.ONMOUSEOVER:
			case Event.ONMOUSEOUT:
				if (mouseListeners != null) {
					mouseListeners.fireMouseEvent(this, event);
				}
				break;

			case Event.ONMOUSEWHEEL:
				if (mouseWheelListeners != null) {
					mouseWheelListeners.fireMouseWheelEvent(this, event);
				}
				break;
		}

	}

	//=========================================================================
	/**
	 * Method removeClickListener
	 * @param listener
	 */
	//=========================================================================
	public void removeClickListener(ClickListener listener) {

		if (clickListeners != null) {
			clickListeners.remove(listener);
		}

	}

	//=========================================================================
	/**
	 * Method removeMouseListener
	 * @param listener
	 */
	//=========================================================================
	public void removeMouseListener(MouseListener listener) {

		if (mouseListeners != null) {
			mouseListeners.remove(listener);
		}

	}

	//=========================================================================
	/**
	 * Method removeMouseWheelListener
	 * @param listener
	 */
	//=========================================================================
	public void removeMouseWheelListener(MouseWheelListener listener) {

		if (mouseWheelListeners != null) {
			mouseWheelListeners.remove(listener);
		}

	}

	//=========================================================================
	/**
	 * Method setDirection
	 * @param direction
	 */
	//=========================================================================
	public void setDirection(Direction direction) {
		BidiUtils.setDirectionOnElement(getElement(), direction);
	}

	//=========================================================================
	/**
	 * Method setHorizontalAlignment
	 * @param align
	 */
	//=========================================================================
	public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
		horzAlign = align;
		DOM.setStyleAttribute(getElement(), "textAlign", align.getTextAlignString());
	}

	//=========================================================================
	/**
	 * Method setText
	 * @param text
	 */
	//=========================================================================
	public void setText(String text) {
		DOM.setInnerText(getElement(), text);
	}

	//=========================================================================
	/**
	 * Method setWordWrap
	 * @param wrap
	 */
	//=========================================================================
	public void setWordWrap(boolean wrap) {
		DOM.setStyleAttribute(getElement(), "whiteSpace", wrap ? "normal" : "nowrap");
	}
}
